package semisupervise;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;

import utils.Opinion;
import utils.Review;

public class MultinomialSemi extends ClassifieurSemi {

	private HashMap<String, Double> betaPositif;
	private HashMap<String, Double> betaNegatif;
	
	/**
	 * Crée un classifieur multinomial qui construit son dictionnaire et apprend
	 * de façon semi-supervisée
	 * 
	 * @param reviews
	 *            Liste de Reviews sur lesquelles construire son dictionnaire et
	 *            apprendre de façon supervisée
	 * @param unlab
	 * 			Liste de Reviews non-étiquetées sur lesquelles tenter
	 * 			d'améliorer l'apprentissage
	 * @param nbIter nombre d'itérations d'apprentissage sur les donées
	 * 			non-étiquetées à effectuer
	 * @param flou Si false, les données non-étiquetées seront étiquetées et
	 * 			leurs étiquettes seront considérées certaines.
	 * 			Si true, les données non-étiquetées seront étiquetées, et
	 * 			leur étiquetage sera complété d'une probabilité d'être vrai
	 */
	public MultinomialSemi(ArrayList<Review> reviews, ArrayList<Review> unlab,
			int nbIter, boolean flou) {
		ArrayList<Review> all = new ArrayList<Review>(reviews);
		all.addAll(unlab);
		construireDictionnaire(all);
		if (!flou)
			apprendre(reviews, unlab, nbIter);
		else
			apprendreFlou(reviews, unlab, nbIter);
	}

	/**
	 * Crée les paramètres beta pour les 2 classes. Les donnnées non-étiquetées
	 * sont étiquetées selon l'apprentissage fait sur les étiquetées. 
	 * Les étiquetages ainsi faits sont considérés certains, au contraire de la
	 * méthode apprendreflou. Les données non-étiquetées peuvent être réévaluées
	 * selon l'apprentissage ainsi fait ensuite, si il y a plusieurs itérations.
	 * 
	 * @param reviews
	 *            Liste des reviews étiquetées
	 * @param unlab
	 *            Liste de reviews non-étiquetées
	 * @param nbIter
	 * 			Nombre d'itérations d'apprentissage. Avec 1, les données non-étiquetées
	 * 			sont évaluées une seule fois, à partir des données étiquetées. Au dessus,
	 * 			les données non-étiquetées sont réévaluées en considérant leur propre évaluation
	 * 			lors de l'itération précédente 
	 */
	private void apprendre(ArrayList<Review> reviews, ArrayList<Review> unlab,
			int nbIter) {
		betaPositif = new HashMap<String, Double>();
		betaNegatif = new HashMap<String, Double>();
		String token;
		int totalPositif = 0, totalNegatif = 0;
		double lisse;

		// On met tout le dictionnaire dans chaque vecteur
		for (String mot : dictionnaire) {
			betaPositif.put(mot, 0.d);
			betaNegatif.put(mot, 0.d);
		}

//		System.out.println("Compte initial...");
		// Pour chaque review étiquetée
		for (Review review : reviews) {
			StringTokenizer tokenizer = new StringTokenizer(review.getTexte(),
					" ");
			// Pour chaque mot
			while (tokenizer.hasMoreTokens()) {
				token = tokenizer.nextToken().toLowerCase();
				// S'il appartient au dico
				if (dictionnaire.contains(token)) {
					// Si c'est dans une review positive
					if (review.isOpinionPositive()) {
						// On ajoute 1 occurrence dans le compte positif
						betaPositif.put(token, betaPositif.get(token) + 1);
						totalPositif++;
					}
					// Si c'est une review negative
					else {
						// On ajoute 1 dans le compte negatif
						betaNegatif.put(token, betaNegatif.get(token) + 1);
						totalNegatif++;
					}
				}
			}// tous les tokens
		}// toutes les review

		// Les beta sont en fait des comptes, qu'on va conserver
		HashMap<String, Double> comptePositif = new HashMap<String, Double>(
				betaPositif);
		HashMap<String, Double> compteNegatif = new HashMap<String, Double>(
				betaNegatif);
		HashMap<String, Double> labelledComptePositif = new HashMap<String, Double>(
				betaPositif);
		HashMap<String, Double> labelledCompteNegatif = new HashMap<String, Double>(
				betaNegatif);

		// On garde aussi les totaux de mots des étiquetés
		int initialTotalPositif = totalPositif;
		int initialTotalNegatif = totalNegatif;

//		System.out.println("Premier compte positif de easy : " +
//		comptePositif.get("easy"));
//		System.out.println("Premier compte negatif de easy : " +
//		compteNegatif.get("easy"));

//		System.out.println("Total positif : " + totalPositif);
//		System.out.println("Total negatif : " + totalNegatif);

		for (int i = 0; i < nbIter; ++i) {
//			System.out.println("Itération " + i);

			// Normalisation lissage
			for (String mot : comptePositif.keySet()) {
				lisse = ((double) (comptePositif.get(mot) + 1) / (double) (totalPositif + 1));
				betaPositif.put(mot, lisse);
			}
			for (String mot : compteNegatif.keySet()) {
				lisse = ((double) (compteNegatif.get(mot) + 1) / (double) (totalNegatif + 1));
				betaNegatif.put(mot, lisse);
			}

//			System.out.println("Beta positif lissé de easy : " +
//			betaPositif.get("easy"));
//			System.out.println("Beta negatif lissé de easy : " +
//			betaNegatif.get("easy"));

			int pos = 0, neg = 0;
//			System.out.println("Evaluations...");
			int changement = 0;
			// Pour chaque review sans label
			for (Review review : unlab) {
				// Si il est positif
				if (getPositifSurNegatif(review) >= 1) {
					// On l'etiquette ainsi
					if (review.isOpinionNegative())
						changement++;
					++pos;
					review.setOpinion(Opinion.POSITIVE);
				}
				// S'il est negatif
				else {
					// Pareil
					if (review.isOpinionPositive())
						changement++;
					++neg;
					review.setOpinion(Opinion.NEGATIVE);
				}
			}
//			System.out.println(changement
//					+ " changement d'avis à cette itération");
//			System.out.println("Ca fait " + pos + " positives et " + neg
//					+ " negatives");

			betaPositif.clear();
			betaNegatif.clear();
			totalPositif = initialTotalPositif;
			totalNegatif = initialTotalNegatif;
			comptePositif = new HashMap<String, Double>(labelledComptePositif);
			compteNegatif = new HashMap<String, Double>(labelledCompteNegatif);

//			System.out.println("Compte...");
			// De nouveau pour les review sans label
			for (Review review : unlab) {
				// On va faire les comptes
				StringTokenizer tokenizer = new StringTokenizer(
						review.getTexte(), " ");
				// Pour chaque mot
				while (tokenizer.hasMoreTokens()) {
					token = tokenizer.nextToken().toLowerCase();
					// S'il appartient au dico
					if (dictionnaire.contains(token)) {
						// Si c'est dans une review positive
						if (review.isOpinionPositive()) {
							// On ajoute 1 occurrence dans le compte positif
							comptePositif.put(token,
									comptePositif.get(token) + 1);
							totalPositif++;
						}
						// Si c'est une review negative
						else {
							// On ajoute 1 dans le compte negatif
							compteNegatif.put(token,
									compteNegatif.get(token) + 1);
							totalNegatif++;
						}
					}
				}// tous les tokens
			}// toutes les unlabelled
//			System.out.println("Apres compte positif de easy : " +
//			comptePositif.get("easy"));
//			System.out.println("Apres compte negatif de easy : " +
//			compteNegatif.get("easy"));
//			System.out.println("Total positifs : " + totalPositif);
//			System.out.println("Total negatifs : " + totalNegatif);
		} // toutes les itérations

//		System.out.println("Nouveau compte positif de easy : " +
//		comptePositif.get("easy"));
//		System.out.println("Nouveau compte negatif de easy : " +
//		compteNegatif.get("easy"));

//		System.out.println("Total positifs : " + totalPositif);
//		System.out.println("Total negatifs : " + totalNegatif);

		// Normalisaton lissage
		for (String mot : comptePositif.keySet()) {
			lisse = ((double) (comptePositif.get(mot) + 1) / (double) (totalPositif + 1));
			betaPositif.put(mot, lisse);
		}
		for (String mot : compteNegatif.keySet()) {
			lisse = ((double) (compteNegatif.get(mot) + 1) / (double) (totalNegatif + 1));
			betaNegatif.put(mot, lisse);
		}

//		System.out.println("Dernier compte positif lissé de easy : " +
//		betaPositif.get("easy"));
//		System.out.println("Dernier compte negatif lissé de easy : " +
//		betaNegatif.get("easy"));
	}
	
	/**
	 * Crée les paramètres beta pour les 2 classes. Les donnnées non-étiquetées
	 * sont étiquetées selon l'apprentissage fait sur les étiquetées. 
	 * On associée à ces etiquetages une probabilité d'être vrais.
	 * Ces probabilités pondèrent l'influence des données non-étiquetées dans les beta.
 	 * Les données non-étiquetées peuvent être réévaluées
	 * selon l'apprentissage ainsi fait ensuite, si il y a plusieurs itérations.
	 * 
	 * @param reviews
	 *            Liste des reviews étiquetées
	 * @param unlab
	 *            Liste de reviews non-étiquetées
	 * @param nbIter
	 * 			Nombre d'itérations d'apprentissage. Avec 1, les données non-étiquetées
	 * 			sont évaluées une seule fois, à partir des données étiquetées. Au dessus,
	 * 			les données non-étiquetées sont réévaluées en considérant leur propre évaluation
	 * 			lors de l'itération précédente 
	 */
	private void apprendreFlou(ArrayList<Review> reviews,
		ArrayList<Review> unlab, int nbIter) {
		betaPositif = new HashMap<String, Double>();
		betaNegatif = new HashMap<String, Double>();
		HashMap<Integer, Double> vraisemblancesPositives
		= new HashMap<Integer, Double>();
		HashMap<Integer, Double> vraisemblancesNegatives
		= new HashMap<Integer, Double>();
		String token;
		int totalPositif = 0, totalNegatif = 0;
		double lisse, vraiPos, vraiNeg;
		double preuvePositive, preuveNegative, apriori;
		double posterieurPositif, posterieurNegatif;
		
		apriori = 1.d/((double)unlab.size());

		// On met tout le dictionnaire dans chaque vecteur
		for (String mot : dictionnaire) {
			betaPositif.put(mot, 0.d);
			betaNegatif.put(mot, 0.d);
		}

		//System.out.println("Compte initial...");
		// Pour chaque review étiquetée
		for (Review review : reviews) {
			StringTokenizer tokenizer = new StringTokenizer(review.getTexte(),
					" ");
			// Pour chaque mot
			while (tokenizer.hasMoreTokens()) {
				token = tokenizer.nextToken().toLowerCase();
				// S'il appartient au dico
				if (dictionnaire.contains(token)) {
					// Si c'est dans une review positive
					if (review.isOpinionPositive()) {
						// On ajoute 1 occurrence dans le compte positif
						betaPositif.put(token, betaPositif.get(token) + 1);
						totalPositif++;
					}
					// Si c'est une review negative
					else {
						// On ajoute 1 dans le compte negatif
						betaNegatif.put(token, betaNegatif.get(token) + 1);
						totalNegatif++;
					}
				}
			}// tous les tokens
		}// toutes les review

		// Les beta sont en fait des comptes, qu'on va conserver
		HashMap<String, Double> comptePositif = new HashMap<String, Double>(
				betaPositif);
		HashMap<String, Double> compteNegatif = new HashMap<String, Double>(
				betaNegatif);
		HashMap<String, Double> labelledComptePositif = new HashMap<String, Double>(
				betaPositif);
		HashMap<String, Double> labelledCompteNegatif = new HashMap<String, Double>(
				betaNegatif);

		// On garde aussi les totaux de mots des étiquetés
		int initialTotalPositif = totalPositif;
		int initialTotalNegatif = totalNegatif;

//		System.out.println("Premier compte positif de easy : " +
//		comptePositif.get("easy"));
//		System.out.println("Premier compte negatif de easy : " +
//		compteNegatif.get("easy"));

//		System.out.println("Total positif : " + totalPositif);
//		System.out.println("Total negatif : " + totalNegatif);

		for (int i = 0; i < nbIter; ++i) {
//			System.out.println("Itération " + i);

//			System.out.println("Compte positif normalisé de easy : " +
//			comptePositif.get("easy"));
//			System.out.println("Compte negatif normalisé de easy : " +
//			compteNegatif.get("easy"));

			// Normalisation et lissage
			for (String mot : comptePositif.keySet()) {
				lisse = ((double) (comptePositif.get(mot) + 1) / (double) (totalPositif + 1));
				betaPositif.put(mot, lisse);
			}
			for (String mot : compteNegatif.keySet()) {
				lisse = ((double) (compteNegatif.get(mot) + 1) / (double) (totalNegatif + 1));
				betaNegatif.put(mot, lisse);
			}

//			System.out.println("Beta positif lissé de easy : " +
//			betaPositif.get("easy"));
//			System.out.println("Beta negatif lissé de easy : " +
//			betaNegatif.get("easy"));

			int pos = 0, neg = 0;
//			System.out.println("Evaluations...");
			
			// On récupère les termes du posterieur pour toutes les reviews
			preuvePositive = 0;
			preuveNegative = 0;
			double maxPos = 0, maxNeg = 0;
			for(Review review: unlab) {
				vraiPos = getLogVraisemblance(review, Opinion.POSITIVE);
				vraiNeg = getLogVraisemblance(review, Opinion.NEGATIVE);
				// Attention, les logvraisemblances sont negatives
				// Le "max" est le plus petit
				if(vraiPos < maxPos) {
					maxPos = vraiPos;
				}
				if(vraiNeg < maxNeg) {
					maxNeg = vraiNeg;
				}
				vraisemblancesPositives.put(review.getId(), vraiPos);
				vraisemblancesNegatives.put(review.getId(), vraiNeg);
			}
//			System.out.println("Max pos " + maxPos + " Max neg " + maxNeg);

			// On transforme les logvraisemblances en probas entre 0.5 et 1
			double tmp, normaPos, normaNeg;
			for(Review review: unlab) {
				tmp = vraisemblancesPositives.get(review.getId());
				normaPos = tmp/maxPos;
//				System.out.println("p " + normaPos);
				vraisemblancesPositives.put(review.getId(), normaPos);
				tmp = vraisemblancesNegatives.get(review.getId());
				normaNeg = tmp/maxNeg;
//				System.out.println("n " + normaNeg);
				vraisemblancesNegatives.put(review.getId(), normaNeg);
				preuvePositive += normaPos;
				preuveNegative += normaNeg;
			}
			preuvePositive *= apriori;
			preuveNegative *= apriori;
			
			// On va etiqueter avec proba les review
			for(Review review : unlab) {
				// On calcule son posterieur pour chaque classe
				posterieurPositif = (vraisemblancesPositives.get(review.getId())
					* apriori) / preuvePositive;
				posterieurNegatif = (vraisemblancesNegatives.get(review.getId())
					* apriori) / preuveNegative;
//				System.out.println("p " + posterieurPositif + " n " + posterieurNegatif);
				
				// Si elle est positive a posteriori
				if(posterieurPositif > posterieurNegatif) {
//					System.out.println(posterieurPositif + " vs. " + posterieurNegatif + " = " + (0.5 + ((0.5 * (posterieurPositif-posterieurNegatif))/posterieurPositif)));
					pos++;
					review.setOpinion(Opinion.POSITIVE);
					review.setProba(posterieurPositif);
				}
				// Si elle est negative a posteriori
				else {
					neg++;
					review.setOpinion(Opinion.NEGATIVE);
					review.setProba(posterieurNegatif);
				}
			}
//			System.out.println("J'ai " + pos + " positives et " + neg + " negatives");
			

			betaPositif.clear();
			betaNegatif.clear();
			totalPositif = initialTotalPositif;
			totalNegatif = initialTotalNegatif;
			comptePositif = new HashMap<String, Double>(labelledComptePositif);
			compteNegatif = new HashMap<String, Double>(labelledCompteNegatif);

//			System.out.println("Compte...");
			// De nouveau pour les review sans label
			for (Review review : unlab) {
				// On va faire les comptes
				StringTokenizer tokenizer = new StringTokenizer(
						review.getTexte(), " ");
				// Pour chaque mot
				while (tokenizer.hasMoreTokens()) {
					token = tokenizer.nextToken().toLowerCase();
					// S'il appartient au dico
					if (dictionnaire.contains(token)) {
						// Si c'est dans une review plutôt positive
						 if(review.isOpinionPositive()) {
							 // On ajoute sa proba dans le compte positif 
							 comptePositif.put(token,
									 comptePositif.get(token) + review.getProba());
							 totalPositif += review.getProba();
							 
						 } // Si c'est une review plutôt negative
						 else {
/*							 if(token.equals("easy")) {
								 System.out.println("Easy avt : " + compteNegatif.get("easy"));
								 System.out.println("Easy proba : " + review.getProba());
							 }
*/							 // On ajoute sa proba dans le compte negatif
							 compteNegatif.put(token,
									 compteNegatif.get(token) +	review.getProba());
							 totalNegatif += review.getProba();
						 }
					}
				}// tous les tokens
			}// toutes les unlabelled
			
//			System.out.println("Apres compte positif de easy : " +
//			comptePositif.get("easy"));
//			System.out.println("Apres compte negatif de easy : " +
//			compteNegatif.get("easy"));
//			System.out.println("Total positifs : " + totalPositif);
//			System.out.println("Total negatifs : " + totalNegatif);
		} // toutes les itérations

//		System.out.println("Nouveau compte positif de easy : " +
//		comptePositif.get("easy"));
//		System.out.println("Nouveau compte negatif de easy : " +
//		compteNegatif.get("easy"));

//		System.out.println("Total positifs : " + totalPositif);
//		System.out.println("Total negatifs : " + totalNegatif);

		// On normalise et lisse une dernière fois
		for (String mot : comptePositif.keySet()) {
			lisse = ((double) (comptePositif.get(mot) + 1) / (double) (totalPositif + 1));
			betaPositif.put(mot, lisse);
		}
		for (String mot : compteNegatif.keySet()) {
			lisse = ((double) (compteNegatif.get(mot) + 1) / (double) (totalNegatif + 1));
			betaNegatif.put(mot, lisse);
		}

//		System.out.println("Dernier compte positif lissé de easy : " +
//		betaPositif.get("easy"));
//		System.out.println("Dernier compte negatif lissé de easy : " +
//		betaNegatif.get("easy"));

	}
	
	/**
	 * Evalue les probabilités d'une liste de reviews
	 * 
	 * @param reviews
	 *            La liste des reviews à évaluer
	 * @return Une map contenant comme clé l'identifiant de la review évaluée,
	 *         et comme valeur true si la review est évaluée positive, false si
	 *         elle est évaluée négative
	 */
	public HashMap<Integer, Boolean> classifier(ArrayList<Review> reviews) {
		StringTokenizer tokenizer;
		String token;
		HashMap<String, Double> compteReview = new HashMap<String, Double>();
		HashMap<Integer, Boolean> resultat = new HashMap<Integer, Boolean>();
		double occurrences;
		double probaPositif, probaNegatif;
		int pos = 0, neg = 0;

//		System.out.println("classifier beta positif de easy : " +
//		betaPositif.get("easy"));
//		System.out.println("classifier beta negatif de easy : " +
//		betaNegatif.get("easy"));

		// Pour chaque review
		for (Review review : reviews) {
			compteReview.clear();
			tokenizer = new StringTokenizer(review.getTexte());
			// Pour chaque mot
			while (tokenizer.hasMoreTokens()) {
				token = tokenizer.nextToken().toLowerCase();
				occurrences = 0.d;
				// S'il est dans le dico
				if (dictionnaire.contains(token)) {
					// Si on l'a deja vu
					if (compteReview.containsKey(token)) {
						// On recupere son nombre d'apparitions
						occurrences = compteReview.get(token);
					}
					// Et on le met dans le compte avec nbOcc +1
					compteReview.put(token, occurrences + 1);
				}
			} // tous les tokens

			// On calcule sa proba d'être positif
			probaPositif = 0.d;
			probaNegatif = 0.d;
			// Pour chaque mot du document
			for (String mot : compteReview.keySet()) {
				probaPositif += Math.log(betaPositif.get(mot))
						* compteReview.get(mot);
				probaNegatif += Math.log(betaNegatif.get(mot))
						* compteReview.get(mot);
			}

//			 System.out.println(probaPositif + " vs. " + probaNegatif);

			// On decide
			if (probaPositif > probaNegatif) {
				resultat.put(review.getId(), true);
				++pos;
			} else {
				resultat.put(review.getId(), false);
				++neg;
			}
		} // toutes les reviews

//		System.out.println("Je vote " + pos + " positives et " + neg
//				+ " negatives");

//		System.out.println("classifier fin beta positif de easy : " +
//		betaPositif.get("easy"));
//		System.out.println("classifier fin beta negatif de easy : " +
//		betaNegatif.get("easy"));
		
		return resultat;
	} // classifier

	/**
	 * Retourne la logvraisemblance qu'une review soit positive divisée
	 * par la logvraisemblance qu'elle soit négative. Ainsi, si le résultat est
	 * supérieur à 1, la review a plus de chances d'être positive. Si le résultat
	 * est inférieur à 0, elle a plus de chances d'être négative
	 * @param review La review donc on veut calculer le rapport des logvraisemblances
	 * @return Le rapport entre la logvraisemblance d'appartenance à la classe positive
	 * et de la logvraisemblance d'appartenance à la classe négative.
	 */
	private double getPositifSurNegatif(Review review) {
		StringTokenizer tokenizer;
		String token;
		HashMap<String, Double> compteReview = new HashMap<String, Double>();
		double occurrences;
		double probaPositif, probaNegatif;

		tokenizer = new StringTokenizer(review.getTexte());
		// Pour chaque mot
		while (tokenizer.hasMoreTokens()) {
			token = tokenizer.nextToken().toLowerCase();
			occurrences = 0.d;
			// S'il est dans le dico
			if (dictionnaire.contains(token)) {
				// Si on l'a deja vu
				if (compteReview.containsKey(token)) {
					// On recupere son nombre d'apparitions
					occurrences = compteReview.get(token);
				}
				// On le met dans le compte avec nbOcc +1
				compteReview.put(token, occurrences + 1);
			}
		} // tous les tokens

		// On calcule sa proba d'être positif et negatif
		probaPositif = 0.d;
		probaNegatif = 0.d;
		// Pour chaque mot du document
		for (String mot : compteReview.keySet()) {
			probaPositif += Math.log(betaPositif.get(mot))
					* compteReview.get(mot);
			probaNegatif += Math.log(betaNegatif.get(mot))
					* compteReview.get(mot);
		}

//		System.out.println(probaPositif + " / " + probaNegatif + " = " +
//		(double)probaPositif/probaNegatif);

		double res = ((double) probaNegatif / (double) probaPositif);
		
//		System.out.print(res + " ");

		return res;
	}

/*	private boolean setProbas(Review review) {
		StringTokenizer tokenizer;
		String token;
		HashMap<String, Double> compteReview = new HashMap<String, Double>();
		double occurrences;
		double probaPositif, probaNegatif;

		tokenizer = new StringTokenizer(review.getTexte());
		// Pour chaque mot
		while (tokenizer.hasMoreTokens()) {
			token = tokenizer.nextToken().toLowerCase();
			occurrences = 0.d;
			// S'il est dans le dico
			if (dictionnaire.contains(token)) {
				// Si on l'a deja vu
				if (compteReview.containsKey(token)) {
					// On recupere son nombre d'apparitions
					occurrences = compteReview.get(token);
				}
				// On le met dans le compte avec nbOcc +1
				compteReview.put(token, occurrences + 1);
			}
		} // tous les tokens

		// On calcule sa proba d'être positif
		probaPositif = 0.d;
		probaNegatif = 0.d;
		// Pour chaque mot du document
		for (String mot : compteReview.keySet()) {
			probaPositif += Math.log(betaPositif.get(mot))
					* compteReview.get(mot);
			probaNegatif += Math.log(betaNegatif.get(mot))
					* compteReview.get(mot);
		}

		double resP, resN = resP = 0;
		//System.out.println("+ " + probaPositif + " = " + Math.exp(probaPositif));
		// S'il est probablement positif
		if (probaPositif > probaNegatif) {
			resP = ((double) (probaNegatif - probaPositif) / probaNegatif);
			// resN = ((double))
//			System.out.println("positif " + resP);
			review.setProbaPositif(resP);
			review.setProbaNegatif(0.d);
			return true;
		} else {
			resN = ((double) (probaNegatif - probaPositif) / Math
					.abs(probaNegatif));
//			System.out.println("negatif " + resN);
			review.setProbaNegatif(resN);
			review.setProbaPositif(0.d);
			return false;
		}
	}
*/

	
	/**
	 * Retourne la logvraisemblance d'une review d'appartenir à un
	 * @param review La review dont on veut la logvraisemblance
	 * @param opinion La classe dont on veut la logvraisemblance
	 * @return La logvraisemblance de la review d'être de l'opinion
	 */
	private double getLogVraisemblance(Review review, Opinion opinion) {
		StringTokenizer tokenizer;
		String token;
		HashMap<String, Double> compteReview = new HashMap<String, Double>();
		double occurrences;
		double proba;
		HashMap<String, Double> beta;
		
		if(opinion.equals(Opinion.POSITIVE)) {
			beta = betaPositif;
		}
		else {
			beta = betaNegatif;
		}

		tokenizer = new StringTokenizer(review.getTexte());
		// Pour chaque mot
		while (tokenizer.hasMoreTokens()) {
			token = tokenizer.nextToken().toLowerCase();
			occurrences = 0.d;
			// S'il est dans le dico
			if (dictionnaire.contains(token)) {
				// Si on l'a deja vu
				if (compteReview.containsKey(token)) {
					// On recupere son nombre d'apparitions
					occurrences = compteReview.get(token);
				}
				// On le met dans le compte avec nbOcc +1
				compteReview.put(token, occurrences + 1);
			}
		} // tous les tokens

		// On calcule sa proba d'être positif
		proba = 0.d;
		// Pour chaque mot du document
		for (String mot : compteReview.keySet()) {
			proba += Math.log(beta.get(mot))
					* compteReview.get(mot);
		}
		return proba;
	}
}
